Os dados coletados são referentes ao dataset disponibilizado no kagle por Rubens Junior (https://www.kaggle.com/rubenssjr/brasilian-houses-to-rent), possuem informações retiradas através de Webcrawler em diversos sites com ofertas de alugueis de imoveis. Os dados contém 10962 observações e 13 vaariaveis. Possuem as seguintes colunas:
city= Cidade; area= Tamanho da casa em m2; rooms= Número de quartos; Bathroom= Número de banheiros; Parking spaces= Número de vagas em estacionamento; Floor= Número de andar; Animal= Se aceita animais ou não; Furniture= Se o local é mobiliado ou não; Hoa= Valor do condominio; rent amount (R\()= Valor do aluguel; property tax (R\))= IPTU da casa; fire insurance (R$)= Seguro de incendio da casa; Total= Total pago ao mês pela casa;
Esse trabalho terá como objetivo prever valores futuros de aluguel utilizando regressão linear
#install.packages("readr")
#install.packages("plotly")
library(readr)
library(visdat)
library(dplyr)
library(ggplot2)
library(plotly)
library(dplyr)
library(corrplot)
library(randomForest)
library(caret)
df<- read_csv("houses_to_rent_v2.csv")
## Parsed with column specification:
## cols(
## city = col_character(),
## area = col_double(),
## rooms = col_double(),
## bathroom = col_double(),
## `parking spaces` = col_double(),
## floor = col_character(),
## animal = col_character(),
## furniture = col_character(),
## `hoa (R$)` = col_double(),
## `rent amount (R$)` = col_double(),
## `property tax (R$)` = col_double(),
## `fire insurance (R$)` = col_double(),
## `total (R$)` = col_double()
## )
head(df)
## # A tibble: 6 x 13
## city area rooms bathroom `parking spaces` floor animal furniture `hoa (R$)`
## <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <chr> <dbl>
## 1 São ~ 70 2 1 1 7 acept furnished 2065
## 2 São ~ 320 4 4 0 20 acept not furn~ 1200
## 3 Port~ 80 1 1 1 6 acept not furn~ 1000
## 4 Port~ 51 2 1 0 2 acept not furn~ 270
## 5 São ~ 25 1 1 0 1 not a~ not furn~ 0
## 6 São ~ 376 3 3 7 - acept not furn~ 0
## # ... with 4 more variables: `rent amount (R$)` <dbl>, `property tax
## # (R$)` <dbl>, `fire insurance (R$)` <dbl>, `total (R$)` <dbl>
Com o objetivo de deixar mais simples a manipulação dos dados e o entendimento, decidimos mudar o nome das variaveis.
names(df)= c("cidade","area","quartos","banheiros","n_estacionamento", "andar","animal","Furniture","condominio","valor_aluguel","IPTU","taxa_incendio","total_pago")
head(df)
## # A tibble: 6 x 13
## cidade area quartos banheiros n_estacionamento andar animal Furniture
## <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <chr>
## 1 São P~ 70 2 1 1 7 acept furnished
## 2 São P~ 320 4 4 0 20 acept not furn~
## 3 Porto~ 80 1 1 1 6 acept not furn~
## 4 Porto~ 51 2 1 0 2 acept not furn~
## 5 São P~ 25 1 1 0 1 not a~ not furn~
## 6 São P~ 376 3 3 7 - acept not furn~
## # ... with 5 more variables: condominio <dbl>, valor_aluguel <dbl>, IPTU <dbl>,
## # taxa_incendio <dbl>, total_pago <dbl>
Inicialmente iremos avaliar se o dataset possuem algum valor faltante.Abaixo é possÃvel perceber que não possuimos nenhum dado faltante, não precisando fazer qualquer tipo de tratamento.
colSums(is.na(df))
## cidade area quartos banheiros
## 0 0 0 0
## n_estacionamento andar animal Furniture
## 0 0 0 0
## condominio valor_aluguel IPTU taxa_incendio
## 0 0 0 0
## total_pago
## 0
Para começarmos a fazer qualquer tipo de analise, precisamos antes de tudo validar se as variaveis do nosso dataset estão formatadas com tipo de dados certo. Para ficar visualmente mais atrativo, decidimos utilizar o pacote visdat.
vis_dat(df)
Precisamos mudar os tipos das variaveis cidade, animal e furniture para o tipo fator. Embora realmente esses dados sejam strigs, elas representam uma variavel de classificação.
df$cidade= as.factor(df$cidade)
df$animal= as.factor(df$animal)
df$Furniture= as.factor(df$Furniture)
df$banheiros=as.integer(df$banheiros)
df
## # A tibble: 10,692 x 13
## cidade area quartos banheiros n_estacionamento andar animal Furniture
## <fct> <dbl> <dbl> <int> <dbl> <chr> <fct> <fct>
## 1 São P~ 70 2 1 1 7 acept furnished
## 2 São P~ 320 4 4 0 20 acept not furn~
## 3 Porto~ 80 1 1 1 6 acept not furn~
## 4 Porto~ 51 2 1 0 2 acept not furn~
## 5 São P~ 25 1 1 0 1 not a~ not furn~
## 6 São P~ 376 3 3 7 - acept not furn~
## 7 Rio d~ 72 2 1 0 7 acept not furn~
## 8 São P~ 213 4 4 4 4 acept not furn~
## 9 São P~ 152 2 2 1 3 acept furnished
## 10 Rio d~ 35 1 1 0 2 acept furnished
## # ... with 10,682 more rows, and 5 more variables: condominio <dbl>,
## # valor_aluguel <dbl>, IPTU <dbl>, taxa_incendio <dbl>, total_pago <dbl>
vis_dat(df)
Com o gráfico abaixo é possÃvel notar que a maioria das casas no dataset são da cidade de São Paulo
g=ggplot(data=df, aes(x=cidade)) + geom_bar(fill="lightblue",)+ coord_flip()+
theme_classic() + labs(title = "Número de casas para alugar por cidades") + ylab("numero de casas")
ggplotly(g)
Analisando agora os valores pagos em alugueis que é a variável que desejamos prever.Abaixo segue algumas analises estatisticas referentes a variavel valor do aluguel agrupadas por cidade
aggregate(df[,"valor_aluguel"], list(local=df$cidade), mean)
## local valor_aluguel
## 1 Belo Horizonte 3664.128
## 2 Campinas 2364.291
## 3 Porto Alegre 2337.700
## 4 Rio de Janeiro 3232.904
## 5 São Paulo 4652.794
aggregate(df[,"valor_aluguel"], list(local=df$cidade), sd)
## local valor_aluguel
## 1 Belo Horizonte 3493.665
## 2 Campinas 2310.903
## 3 Porto Alegre 2199.696
## 4 Rio de Janeiro 2804.266
## 5 São Paulo 3634.612
aggregate(df[,"valor_aluguel"], list(local=df$cidade), max)
## local valor_aluguel
## 1 Belo Horizonte 15000
## 2 Campinas 15000
## 3 Porto Alegre 19000
## 4 Rio de Janeiro 15000
## 5 São Paulo 45000
aggregate(df[,"valor_aluguel"], list(local=df$cidade), min)
## local valor_aluguel
## 1 Belo Horizonte 450
## 2 Campinas 500
## 3 Porto Alegre 500
## 4 Rio de Janeiro 500
## 5 São Paulo 500
aggregate(df[,"valor_aluguel"], list(local=df$cidade), median)
## local valor_aluguel
## 1 Belo Horizonte 2300
## 2 Campinas 1500
## 3 Porto Alegre 1650
## 4 Rio de Janeiro 2300
## 5 São Paulo 3400
Iremos avaliar agora como andam os valores outilines, é possivel já notar pelo desvio padrão que possuimos um conjunto de dados bastante esparço em relação a variavel valor_aluguel.Agora iremos visualizar através de um boxplot
lista=c("banheiros","quartos","n_estacionamento")
legenda=c("Valor do aluguel pela quantidade de banheiros",
"Valor do alguel pela quantidade de quartos",
"Valor do aluguel pela quantidade de n_estacionamento")
plot.boxes<-function(X,legenda){
ggplot(df,aes_string(x=X, y="valor_aluguel",group=X))+
geom_boxplot() + labs(title = legenda)+
theme_classic()
}
Map(plot.boxes,lista,legenda)
## $banheiros
##
## $quartos
##
## $n_estacionamento
É possivel notar que as 3 variaveis possuem uma correlação com o valor do aluguel e possuem varios outlines.Decidimos não remove-los e deixa-los no modelo preditivo, pois sua remoção poderia criar um modelo que não representaria a realidade.
Finalizando a nossa analise exploratoria, abaixo segue uma gráfico que mostra a correlação entre as variaveis
colnumericas=sapply(df, is.numeric)
correlacao= cor(df[,colnumericas])
corrplot(correlacao, method = "color",addCoef.col =T)
É possivel notar uma correlação positiva média a forte entre as variaveis taxa de incendio, número de quartos, número de banheiros e número de vagas de estacionamento com a váriavel valor do aluguel. (Outra correlação muito forte é com o total pago, mas essa variavel não ajudará de nada nosso modelo, pois seu valor depende do preço do aluguel)
Agora utilizaremos um modelo randomForest para criar um modelo com o objetivo de avaliar quais as variaveis mais importantes para prever o valor do aluguel
modelo= randomForest(valor_aluguel~.-total_pago,df,ntree=100,nodesize=10,
importance=T)
#Plotando nivel de importancia
varImpPlot(modelo)
Com o nÃvel de importancia das variaveis, podemos saber quais variaveis tem o maior impacto para prever a variável valor do aluguel
Primeiramento separamos o nosso conjunto de dados em um dataset de treino e outro de teste, 70% dos dados serão utilizados para treinar o modelo e 30% para avaliar a eficácia do mesmo.
set.seed(00)
split<- createDataPartition(df$cidade,p=0.7, list=F)
dados_treino= df[split,]
## Warning: The `i` argument of ``[`()` can't be a matrix as of tibble 3.0.0.
## Convert to a vector.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.
dados_teste=df[-split,]
Iremos agora criar o modelo de regressão utilizando apenas as variaveis mais importantes encontradas no feacture select.Seram retirados as variáveis Animal e mobilia por não terem uma significancia para nossa previsão.
dados_treino$andar=NULL
dados_teste$andar=NULL
modeloLinear<- train(valor_aluguel~.-total_pago -animal
-Furniture,data=dados_treino, method="lm")
Com o modelo criado será utilizado os dados de testes para avaliar a precisão do modelo criado
previsao<- predict(modeloLinear,dados_teste)
#Dataframe com valor real e valor previsto
score= as.data.frame(cbind(dados_teste$valor_aluguel,previsao))
names(score)=c("Valor_real","Valor_previsto")
head(score)
## Valor_real Valor_previsto
## 1 3300 3198.164
## 2 2800 2700.631
## 3 2300 2418.738
## 4 4370 4207.622
## 5 8000 8564.544
## 6 3000 3048.444
Analisando o modelo criado, conseguimos um R-squared de 0.98 indicando que a reta criada se adaptou bem aos dados apresentados.
summary(modeloLinear)
##
## Call:
## lm(formula = .outcome ~ ., data = dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4567.0 -191.4 1.4 183.7 10642.6
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.960e+01 2.317e+01 0.846 0.39757
## cidadeCampinas 1.648e+02 2.706e+01 6.091 1.18e-09 ***
## `cidadePorto Alegre` -1.589e+02 2.482e+01 -6.404 1.61e-10 ***
## `cidadeRio de Janeiro` 2.930e+02 2.370e+01 12.360 < 2e-16 ***
## `cidadeSão Paulo` 3.375e+02 1.924e+01 17.547 < 2e-16 ***
## area -5.530e-02 1.797e-02 -3.077 0.00210 **
## quartos -7.144e+01 7.793e+00 -9.168 < 2e-16 ***
## banheiros 6.536e+01 7.417e+00 8.812 < 2e-16 ***
## n_estacionamento -3.901e+01 5.534e+00 -7.049 1.96e-12 ***
## condominio 9.597e-04 3.180e-04 3.018 0.00256 **
## IPTU 2.247e-03 1.591e-03 1.412 0.15789
## taxa_incendio 7.045e+01 1.747e-01 403.381 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 504.7 on 7475 degrees of freedom
## Multiple R-squared: 0.978, Adjusted R-squared: 0.978
## F-statistic: 3.024e+04 on 11 and 7475 DF, p-value: < 2.2e-16
Agora com base nos valores previstos a partir da base de testes, iremos analisar os residuos gerados com base no valor real do aluguel e no valor que o modelo previu.
Avaliando os residuos é possÃvel notar que criamos um bom modelo pelo fato do mesmo seguir uma normal tendendo a zero. Embora possuimos alguns valores que representam os residuos dos pontos fora da curva.
residuo<- function(real,previsto){
return(previsto-real)
}
residu=as.data.frame(mapply( residuo,score$Valor_real,score$Valor_previsto))
names(residu)="residuo"
ggplot(residu,aes(x=residuo), with=600) +geom_histogram(bins=50)+
xlim(c(-2500,2500)) + theme_classic() + labs(title = "ResÃduos entre valores reais e previstos")
Em seguida foi plotado os valores reais e previstos em um gráfico para visualizar a diferença entre os valores. É possÃvel notar que os valores ficaram bem proximos um dos outros, mostrando que a análise foi bastante eficaz. Foi mostrado apenas os 500 primeiros valores previstos por motivos de melhor visualização.
score$index=c(1:3205)
ggplotly(ggplot(data=score, aes(x=index,y=Valor_real))+ geom_line(color="red") + labs(title = "Valores Previstos e reais") +geom_line(data=score, aes(x=index, y=Valor_previsto)) +theme_classic() + xlim(c(0,500)))